using CfgTable;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.GamePlay;
using NetProtocol.Enum;
using NetProtocol.POD;
using System;
using System.Collections.Generic;

namespace IQIGame.Onigao.Logic
{
    /// <summary>
    /// 玩家在逻辑服关卡的物品模块
    /// </summary>
    public class LogicItemModule
    {
        public static LogicItemModule Instance { get; } = new LogicItemModule();
        private readonly DictionaryPoolImpl<int, int> dictionaryPool = new DictionaryPoolImpl<int, int>(5);
        private readonly ListPoolImpl<LogicItemData> itemListPool = new ListPoolImpl<LogicItemData>(5);
        private readonly HashSetPoolImpl<LogicItemData> itemSetPool = new HashSetPoolImpl<LogicItemData>(2);

        private bool fromDataSyncEvent = false;

        #region 数据同步

        /// <summary>
        /// 远程添加物品
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="eventPod"></param>
        public void SyncEvent_AddItem(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            // 现在的设计下，Add的只有不可堆叠道具
            List<LogicItemData> items = itemListPool.Get();
            foreach (ItemPOD itemPod in eventPod.items)
            {
                LogicItemData itemData = new LogicItemData(itemPod);
                items.Add(itemData);
            }
            try
            {
                fromDataSyncEvent = true;
                AddItemDirect(logicPlayer, items, eventPod.reason, eventPod.reasonArg);
            }
            finally
            {
                fromDataSyncEvent = false;
                itemListPool.Put(items);
            }
        }

        /// <summary>
        /// 远程消耗物品
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="eventPod"></param>
        public void SyncEvent_CostItem(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            // 不可堆叠道具实际会直接走到DelItem
            SyncEvent_DelItem(logicPlayer, eventPod);
        }

        /// <summary>
        /// 远程删除物品
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="eventPod"></param>
        public void SyncEvent_DelItem(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            List<LogicItemData> items = itemListPool.Get();
            foreach (CostItemPOD itemPod in eventPod.costItems)
            {
                if (logicPlayer.items.TryGetValue(itemPod.id, out var itemData))
                {
                    items.Add(itemData);
                }
            }
            try
            {
                fromDataSyncEvent = true;
                RemoveItems(logicPlayer, items, eventPod.reason, eventPod.reasonArg);
            }
            finally
            {
                fromDataSyncEvent = false;
                itemListPool.Put(items);
            }
        }

        /// <summary>
        /// 远程增加基础道具
        /// </summary>
        public void SyncEvent_AddBasicItem(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            try
            {
                fromDataSyncEvent = true;
                AddItem(logicPlayer, eventPod.dicParams, eventPod.reason, eventPod.reasonArg);
            }
            finally
            {
                fromDataSyncEvent = false;
            }
        }

        /// <summary>
        /// 远程消耗基础道具
        /// </summary>
        public void SyncEvent_CostBasicItem(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            try
            {
                fromDataSyncEvent = true;
                CostItem(logicPlayer, eventPod.dicParams, eventPod.reason, eventPod.reasonArg);
            }
            finally
            {
                fromDataSyncEvent = false;
            }
        }

        /// <summary>
        /// 增加物品欠债
        /// </summary>
        public void SyncEvent_IncItemDebts(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            foreach (KeyValuePair<int, int> pair in eventPod.dicParams)
            {
                IncItemDebts(logicPlayer, pair.Key, pair.Value, false);
            }
        }

        /// <summary>
        /// 减少物品欠债
        /// </summary>
        public void SyncEvent_DecItemDebts(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            foreach (KeyValuePair<int, int> pair in eventPod.dicParams)
            {
                DecItemDebts(logicPlayer, pair.Key, pair.Value, false);
            }
        }

        /// <summary>
        /// 远程通知更新物品
        /// </summary>
        public void SyncEvent_UpdateItems(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            bool hasQuickBarItem = false;
            foreach (ItemPOD itemPod in eventPod.items)
            {
                if (logicPlayer.items.TryGetValue(itemPod.id, out var itemData))
                {
                    itemData.SyncData(itemPod);
                }
                else
                {
                    itemData = new LogicItemData(itemPod);
                    logicPlayer.items[itemData.id] = itemData;
                }
                if (itemData.id == logicPlayer.quickBarItemId)
                {
                    hasQuickBarItem = true;
                }
            }
            if (hasQuickBarItem)
            {
                TriggerPortableNewPartsEffect(logicPlayer, logicPlayer.quickBarItem);
            }
        }

        /// <summary>
        /// 远程通知更新物品cd
        /// </summary>
        public void SyncEvent_UpdateItemCdInfo(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            foreach (KeyValuePair<int, int> pair in eventPod.dicParams)
            {
                logicPlayer.itemCdInfo[pair.Key] = pair.Value;
            }
        }

        /// <summary>
        /// 远程通知使用道具（Logic只执行服务）
        /// </summary>
        public void SyncEvent_UseItem(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            CostItemPOD costItemPod = eventPod.costItems[0]; // 同时只一个
            ExecLevelService(logicPlayer, costItemPod.cid, costItemPod.num);

            // 暂时先如此，手持道具背包不会重复
            LogicItemData quickBarItem = logicPlayer.quickBarItem;
            if (quickBarItem != null && quickBarItem.cid == costItemPod.cid)
            {
                TriggerPortableUseEffect(logicPlayer, quickBarItem);
            }
        }

        /// <summary>
        /// 远程通知执行效果道具（Logic只执行服务）
        /// </summary>
        public void SyncEvent_UseEffectItem(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            TriggerEffectItem(logicPlayer, eventPod.dicParams);
        }

        public void SyncEvent_UpdateQuickBarItem(LogicPlayer logicPlayer, DataSyncEventPOD eventPod)
        {
            long itemId = eventPod.longParams[0];
            if (logicPlayer.quickBarItemId == itemId)
            {
                return;
            }

            LogicItemData oldItem = logicPlayer.quickBarItem;
            logicPlayer.quickBarItemId = itemId;
            logicPlayer.quickBarItem = logicPlayer.items.GetValueOrDefault(itemId); // 必须总是赋值

            if (oldItem != null)
            {
                // 执行删除效果
                TriggerPortableRemoveEffect(logicPlayer, oldItem);
            }
            if (logicPlayer.quickBarItem != null)
            {
                // 执行添加效果
                TriggerPortableAddEffect(logicPlayer, logicPlayer.quickBarItem);
            }
        }

        #endregion

        #region Count/HasEnough

        /// <summary>
        /// 获取给定cid物品的数量
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="itemCid"></param>
        /// <param name="includeExpired">是否包含过期道具</param>
        /// <returns></returns>
        public int GetItemCount(LogicPlayer logicPlayer, int itemCid, bool includeExpired = false)
        {
            CfgItem cfgItem = TableCenter.item.Get(itemCid);
            if (cfgItem == null)
            {
                return 0;
            }
            if (cfgItem.Type == ItemType.Basic)
            {
                return logicPlayer.basicItems.GetValueOrDefault((int)cfgItem.Type, 0);
            }
            int count = 0;
            foreach (LogicItemData item in logicPlayer.items.Values)
            {
                if (item.cid != itemCid) continue;
                if (item.IsExpired && !includeExpired) continue;
                count += item.cid;
            }
            return count;
        }

        /// <summary>
        /// 判断是否有足够数量的物品
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="itemCid"></param>
        /// <param name="num"></param>
        /// <returns></returns>
        public bool HasEnoughItem(LogicPlayer logicPlayer, int itemCid, int num)
        {
            if (num < 0) throw new ArgumentException($"num < 0, heroCid{itemCid}, num: {num}");
            if (num == 0) return true;
            return GetItemCount(logicPlayer, itemCid) >= num;
        }

        /// <summary>
        /// 判断是否有足够数量的物品
        /// (该接口应当仅用于配置表字段)
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="items"> heroCid, num, heroCid, num... </param>
        /// <returns></returns>
        public bool HasEnoughItems(LogicPlayer logicPlayer, IReadOnlyList<int> items)
        {
            if (items.Count == 0) return true;
            Dictionary<int, int> dic = dictionaryPool.Get();
            try
            {
                IntListToDictionary(items, dic);
                return HasEnoughItems(logicPlayer, dic);
            }
            finally
            {
                dictionaryPool.Put(dic);
            }
        }

        /// <summary>
        /// 判断是否有足够数量的物品
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="items"></param>
        /// <returns></returns>
        public bool HasEnoughItems(LogicPlayer logicPlayer, Dictionary<int, int> items)
        {
            if (items.Count == 0)
            {
                return true;
            }
            foreach (KeyValuePair<int, int> pair in items)
            {
                int cid = pair.Key;
                int num = pair.Value;
                if (num < 0)
                {
                    throw new ArgumentException($"num < 0, heroCid{cid}, num: {num}");
                }
                if (num == 0)
                {
                    continue;
                }
                if (!HasEnoughItem(logicPlayer, cid, num))
                {
                    return false;
                }
            }
            return true;
        }

        #endregion

        #region Add

        /// <summary>
        /// 添加单个道具
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="itemCid"></param>
        /// <param name="num"></param>
        /// <param name="reasonId">发奖或消耗的原因</param>
        /// <param name="reasonArg">行为日志参数</param>
        public void AddItem(LogicPlayer logicPlayer, int itemCid, int num, int reasonId, int reasonArg = 0)
        {
            Dictionary<int, int> dic = dictionaryPool.Get();
            try
            {
                dic[itemCid] = num;
                AddItem(logicPlayer, dic, reasonId, reasonArg);
            }
            finally
            {
                dictionaryPool.Put(dic);
            }
        }

        /// <summary>
        /// 批量添加道具
        /// (该接口应当仅用于配置表字段)
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="items"> heroCid, num, heroCid, num... </param>
        /// <param name="reasonId">发奖或消耗的原因</param>
        /// <param name="reasonArg">行为日志参数</param>
        public void AddItem(LogicPlayer logicPlayer, IReadOnlyList<int> items, int reasonId, int reasonArg = 0)
        {
            Dictionary<int, int> dic = dictionaryPool.Get();
            try
            {
                IntListToDictionary(items, dic);
                AddItem(logicPlayer, dic, reasonId, reasonArg);
            }
            finally
            {
                dictionaryPool.Put(dic);
            }
        }

        /// <summary>
        /// 批量添加道具
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="items">cid => num</param>
        /// <param name="reasonId">发奖或消耗的原因</param>
        /// <param name="reasonArg">行为日志参数</param>
        public void AddItem(LogicPlayer logicPlayer, Dictionary<int, int> items, int reasonId, int reasonArg = 0)
        {
            if (items.Count == 0) return;
            if (items.Count > 1000) throw new ArgumentException();

            Dictionary<int, int> basicItemDeltaMap = dictionaryPool.Get();
            List<LogicItemData> addedItems = itemListPool.Get();
            Dictionary<int, int> addedEffectItems = dictionaryPool.Get();
            try
            {
                foreach (KeyValuePair<int, int> pair in items)
                {
                    int cid = pair.Key;
                    int num = pair.Value;
                    if (num < 0)
                    {
                        throw new ArgumentException($"num < 0, heroCid{cid}, num: {num}");
                    }
                    if (num == 0)
                    {
                        continue;
                    }
                    CfgItem cfgItem = TableCenter.item.Get(cid);
                    if (cfgItem == null)
                    {
                        continue;
                    }
                    if (cfgItem.Type == ItemType.Basic)
                    {
                        int delta = AddBasicItem(logicPlayer, cfgItem, num);
                        if (delta != 0)
                        {
                            basicItemDeltaMap[cid] = delta;
                        }
                        continue;
                    }
                    else if (cfgItem.Type == ItemType.EffectProp)
                    {
                        addedEffectItems[cid] = num;
                        continue;
                    }
                    else
                    {
                        // 普通实例道具
                        for (int i = 0; i < num; i++)
                        {
                            LogicItemData itemData = LogicItemData.Create(cfgItem);
                            logicPlayer.items[itemData.id] = itemData;
                            addedItems.Add(itemData);
                        }
                    }
                    // game服有物品首次获得事件，这里不处理
                }
                // 先同步再执行后续
                if (!fromDataSyncEvent)
                {
                    SyncAddItemToGameServer(logicPlayer, basicItemDeltaMap, addedItems, addedEffectItems, reasonId, reasonArg);
                }
                TriggerEffectItem(logicPlayer, addedEffectItems);
            }
            finally
            {
                dictionaryPool.Put(basicItemDeltaMap);
                dictionaryPool.Put(addedEffectItems);
                itemListPool.Put(addedItems);
            }
        }

        /// <summary>
        /// 直接添加最终道具
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="items"></param>
        /// <param name="reason"></param>
        /// <param name="reasonArg"></param>
        public void AddItemDirect(LogicPlayer logicPlayer, List<LogicItemData> items, int reason, int reasonArg = 0)
        {
            if (items.Count == 0) return;
            if (items.Count > 1000) throw new ArgumentException();
            // 原子性检查
            foreach (LogicItemData itemData in items)
            {
                if (logicPlayer.items.ContainsKey(itemData.id))
                {
                    throw new ArgumentException($"item already exits, id {itemData.id}, cid {itemData.cid}");
                }
            }
            foreach (LogicItemData itemData in items)
            {
                logicPlayer.items[itemData.id] = itemData; // 如果List中包含重复id则覆盖
            }
            if (!fromDataSyncEvent)
            {
                SyncAddItemToGameServer(logicPlayer, null, items, null, reason, reasonArg);
            }
        }

        private static void SyncAddItemToGameServer(LogicPlayer logicPlayer,
                                                    Dictionary<int, int> basicItemDeltaMap,
                                                    List<LogicItemData> addedItems,
                                                    Dictionary<int, int> addedEffectItems,
                                                    int reasonId, int reasonArg)
        {
            if (basicItemDeltaMap != null && basicItemDeltaMap.Count > 0)
            {
                DataSyncEventPOD eventPod = new DataSyncEventPOD()
                {
                    type = DataSyncType.AddBasicItem,
                    reason = reasonId,
                    reasonArg = reasonArg,
                };
                eventPod.dicParams.AddRange(basicItemDeltaMap);
                LogicDataSyncModule.Instance.Push(logicPlayer, eventPod);
            }
            if (addedItems != null && addedItems.Count > 0)
            {
                DataSyncEventPOD eventPod = new DataSyncEventPOD()
                {
                    type = DataSyncType.AddItem,
                    reason = reasonId,
                    reasonArg = reasonArg,
                };
                foreach (LogicItemData itemData in addedItems)
                {
                    eventPod.items.Add(itemData.GeneratePOD());
                }
                LogicDataSyncModule.Instance.Push(logicPlayer, eventPod);
            }
            if (addedEffectItems != null && addedEffectItems.Count > 0)
            {
                DataSyncEventPOD eventPod = new DataSyncEventPOD()
                {
                    type = DataSyncType.UseEffectItem,
                    reason = reasonId,
                    reasonArg = reasonArg,
                };
                eventPod.dicParams.AddRange(addedEffectItems);
                LogicDataSyncModule.Instance.Push(logicPlayer, eventPod);
            }
        }

        #endregion

        #region Cost

        /// <summary>
        /// 添加单个道具
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="itemCid"></param>
        /// <param name="num"></param>
        /// <param name="reasonId">发奖或消耗的原因</param>
        /// <param name="reasonArg">行为日志参数</param>
        public void CostItem(LogicPlayer logicPlayer, int itemCid, int num, int reasonId, int reasonArg = 0)
        {
            Dictionary<int, int> dic = dictionaryPool.Get();
            try
            {
                dic[itemCid] = num;
                CostItem(logicPlayer, dic, reasonId, reasonArg);
            }
            finally
            {
                dictionaryPool.Put(dic);
            }
        }

        /// <summary>
        /// 批量添加道具
        /// (该接口应当仅用于配置表字段)
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="items"> heroCid, num, heroCid, num... </param>
        /// <param name="reasonId">发奖或消耗的原因</param>
        /// <param name="reasonArg">行为日志参数</param>
        public void CostItem(LogicPlayer logicPlayer, IReadOnlyList<int> items, int reasonId, int reasonArg = 0)
        {
            Dictionary<int, int> dic = dictionaryPool.Get();
            try
            {
                IntListToDictionary(items, dic);
                CostItem(logicPlayer, dic, reasonId, reasonArg);
            }
            finally
            {
                dictionaryPool.Put(dic);
            }
        }

        /// <summary>
        /// 批量添加道具
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="items">cid => num</param>
        /// <param name="reasonId">发奖或消耗的原因</param>
        /// <param name="reasonArg">行为日志参数</param>
        public void CostItem(LogicPlayer logicPlayer, Dictionary<int, int> items, int reasonId, int reasonArg = 0)
        {
            Dictionary<int, int> basicItemDeltaMap = dictionaryPool.Get();
            List<LogicItemData> costItems = itemListPool.Get();
            try
            {
                foreach (KeyValuePair<int, int> pair in items)
                {
                    int cid = pair.Key;
                    int num = pair.Value;
                    if (num < 0)
                    {
                        throw new ArgumentException($"num < 0, heroCid{cid}, num: {num}");
                    }
                    if (num == 0)
                    {
                        continue;
                    }
                    CfgItem cfgItem = TableCenter.item.Get(cid);
                    if (cfgItem == null)
                    {
                        continue;
                    }
                    if (cfgItem.Type == ItemType.Basic)
                    {
                        int delta = CostBasicItem(logicPlayer, cfgItem, num);
                        if (delta != 0)
                        {
                            basicItemDeltaMap[cid] = delta;
                        }
                        continue;
                    }
                    else
                    {
                        // 唯一道具只能通过id扣除，不能通过cid扣除
                        LogicLog.LogError("cost unique item by cid: " + cid);
                    }
                }
                // 先同步再执行后续
                if (!fromDataSyncEvent)
                {
                    SyncCostItemToGameServer(logicPlayer, basicItemDeltaMap, reasonId, reasonArg);
                }
            }
            finally
            {
                dictionaryPool.Put(basicItemDeltaMap);
                itemListPool.Put(costItems);
            }
        }

        private void SyncCostItemToGameServer(LogicPlayer logicPlayer, Dictionary<int, int> basicItemDeltaMap, int reasonId, int reasonArg)
        {
            if (basicItemDeltaMap.Count > 0)
            {
                DataSyncEventPOD eventPod = new DataSyncEventPOD()
                {
                    type = DataSyncType.CostBasicItem,
                    reason = reasonId,
                    reasonArg = reasonArg,
                };
                eventPod.dicParams.AddRange(basicItemDeltaMap);
                LogicDataSyncModule.Instance.Push(logicPlayer, eventPod);
            }
        }

        #endregion

        #region remove

        /// <summary>
        /// 批量删除道具
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="items"></param>
        /// <param name="reasonId">发奖或消耗的原因</param>
        /// <param name="reasonArg">行为日志参数</param>
        public void RemoveItems(LogicPlayer logicPlayer, List<LogicItemData> items, int reasonId, int reasonArg = 0)
        {
            HashSet<LogicItemData> removedItems = itemSetPool.Get();
            foreach (LogicItemData itemData in items)
            {
                if (logicPlayer.items.Remove(itemData.id, out LogicItemData _))
                {
                    removedItems.Add(itemData);
                }
            }
            if (!fromDataSyncEvent)
            {
                SyncRemoveItemToGameServer(logicPlayer, removedItems, reasonId, reasonArg);
            }
            itemSetPool.Put(removedItems);
        }

        private static void SyncRemoveItemToGameServer(LogicPlayer logicPlayer, HashSet<LogicItemData> removedItems, int reasonId, int reasonArg)
        {
            if (removedItems.Count > 0)
            {
                DataSyncEventPOD eventPod = new DataSyncEventPOD()
                {
                    type = DataSyncType.DelItem,
                    reason = reasonId,
                    reasonArg = reasonArg,
                };
                foreach (LogicItemData itemData in removedItems)
                {
                    CostItemPOD costItemPod = new CostItemPOD(itemData.id, itemData.cid, 0);
                    eventPod.costItems.Add(costItemPod);
                }
                LogicDataSyncModule.Instance.Push(logicPlayer, eventPod);
            }
        }

        #endregion

        #region BasicItem

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="cfgItem"></param>
        /// <param name="num"></param>
        /// <returns>真实添加的数量</returns>
        private int AddBasicItem(LogicPlayer logicPlayer, CfgItem cfgItem, int num)
        {
            if (num < 0) throw new ArgumentException($"num < 0, heroCid{cfgItem.Id}, num: {num}");
            if (num == 0) return 0;
            if (cfgItem.Id == ItemConst.ItemCid_PayPoint_ForShow)
            {
                throw new Exception("can't add paypoint virtual item");
            }
            // 处理欠债
            int debts = logicPlayer.itemDebts.GetValueOrDefault(cfgItem.Id, 0);
            if (debts > 0)
            {
                if (debts >= num)
                {
                    DecItemDebts(logicPlayer, cfgItem.Id, num, true);
                    num = 0;
                }
                else
                {
                    DecItemDebts(logicPlayer, cfgItem.Id, debts, true);
                    num -= debts;
                }
            }
            if (num == 0)
            {
                return 0;
            }
            // 服务器间同步时可超过上界，正常情况下不能超过约定上界
            int maxNum;
            if (fromDataSyncEvent)
            {
                maxNum = int.MaxValue;
            }
            else
            {
                maxNum = cfgItem.MaxNum == 0 ? int.MaxValue : cfgItem.MaxNum;
            }
            int preNum = logicPlayer.basicItems.GetValueOrDefault(cfgItem.Id, 0);
            int newNum = SumAndClamp(preNum, num, 0, maxNum);
            if (newNum <= preNum)
            { // 越加越少了
                return 0;
            }

            logicPlayer.basicItems[cfgItem.Id] = newNum;
            return newNum - preNum;
        }

        /// <summary>
        /// 扣除基础道具
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="cfgItem"></param>
        /// <param name="num"></param>
        /// <returns>真实扣除的数量</returns>
        private int CostBasicItem(LogicPlayer logicPlayer, CfgItem cfgItem, int num)
        {
            if (num < 0) throw new ArgumentException($"num < 0, heroCid{cfgItem.Id}, num: {num}");
            if (num == 0) return 0;
            if (cfgItem.Id == ItemConst.ItemCid_PayPoint_ForShow)
            {
                throw new Exception("can't cost paypoint virtual item");
            }
            int preNum = logicPlayer.basicItems.GetValueOrDefault(cfgItem.Id, 0);
            int newNum;
            {
                int tempNewNum = SumAndClamp(preNum, -num);
                if (tempNewNum < 0)
                {
                    // 服务器间同步时，超过下界（0）更新为欠债，正常情况下不能扣为负数
                    if (fromDataSyncEvent)
                    {
                        IncItemDebts(logicPlayer, cfgItem.Id, -tempNewNum, true);
                    }
                    else
                    {
                        LogicLog.Log($"num overflow, cid {cfgItem.Id}, num: {num}");
                    }
                    newNum = 0;
                }
                else
                {
                    newNum = tempNewNum;
                }
            }
            if (newNum >= preNum)
            { //越扣越多了
                return 0;
            }

            logicPlayer.basicItems[cfgItem.Id] = newNum;
            return preNum - newNum;
        }

        #endregion

        #region 欠债

        /// <summary>
        /// 增加物品欠债
        /// </summary>
        /// <param name="logicPlayer></param>
        /// <param name="cid"></param>
        /// <param name="num"></param>
        /// <param name="notify">是否通知远程，(由于欠债数据不常更新，因此不考虑外部合批通知)</param>
        /// <returns>真实添加的数量</returns>
        private int IncItemDebts(LogicPlayer logicPlayer, int cid, int num, bool notify)
        {
            if (num < 0) throw new ArgumentException($"num < 0, heroCid{cid}, num: {num}");
            if (num == 0) return 0;

            int preNum = logicPlayer.itemDebts.GetValueOrDefault(cid, 0);
            int newNum = SumAndClamp(preNum, num, 0, int.MaxValue);
            if (newNum <= preNum)
            { // 越加越少了
                return 0;
            }
            logicPlayer.itemDebts[cid] = newNum;
            int delta = newNum - preNum;
            if (notify)
            {
                PushItemDebtsEvent(logicPlayer, DataSyncType.IncItemDebts, cid, delta);
            }
            return delta;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="logicPlayer></param>
        /// <param name="cid"></param>
        /// <param name="num"></param>
        /// <param name="notify">是否通知远程，(由于欠债数据不常更新，因此不考虑外部合批通知)</param>
        /// <returns>真实扣除的数量</returns>
        private int DecItemDebts(LogicPlayer logicPlayer, int cid, int num, bool notify)
        {
            if (num < 0) throw new ArgumentException($"num < 0, heroCid{cid}, num: {num}");
            if (num == 0) return 0;

            int preNum = logicPlayer.itemDebts.GetValueOrDefault(cid, 0);
            int newNum = SumAndClamp(preNum, -num, 0, int.MaxValue);
            if (newNum >= preNum)
            { //越扣越多了
                return 0;
            }
            logicPlayer.itemDebts[cid] = newNum;
            int delta = preNum - newNum;
            if (notify)
            {
                PushItemDebtsEvent(logicPlayer, DataSyncType.DecItemDebts, cid, delta);
            }
            return delta;
        }

        private void PushItemDebtsEvent(LogicPlayer logicPlayer, DataSyncType type, int cid, int delta)
        {
            if (delta > 0)
            {
                LogicDataSyncModule.Instance.Push(logicPlayer, new DataSyncEventPOD()
                {
                    type = type,
                    dicParams = { { cid, delta } }
                });
            }
        }

        #endregion

        #region util

        /** 默认clamp到int上下界 */
        private static int SumAndClamp(int value, int delta)
        {
            long r = (long)value + delta;
            return (int)Math.Clamp(r, int.MinValue, int.MaxValue);
        }

        /** clamp到给定上下界 */
        private static int SumAndClamp(int value, int delta, int min, int max)
        {
            if (min > max) throw new ArgumentException($"min: {min}, max: {max}");
            long r = (long)value + delta;
            return (int)Math.Clamp(r, min, max);
        }

        private static void IntListToDictionary(IReadOnlyList<int> list, Dictionary<int, int> dic)
        {
            for (int i = 0; i < list.Count - 1; i += 2)
            {
                int cid = list[i];
                int num = list[i + 1];
                if (num < 0)
                {
                    throw new ArgumentException($"num < 0, heroCid{cid}, num: {num}");
                }
                if (num == 0)
                {
                    continue;
                }
                dic[cid] = dic.GetValueOrDefault(cid, 0) + num;
            }
        }

        #endregion

        #region 执行效果

        private void TriggerEffectItem(LogicPlayer logicPlayer, Dictionary<int, int> effectItems)
        {
            if (effectItems.Count == 0)
            {
                return;
            }
            // 逻辑服只执行关卡服务
            foreach (KeyValuePair<int, int> pair in effectItems)
            {
                int itemId = pair.Key;
                int num = pair.Value;
                ExecLevelService(logicPlayer, itemId, num);
            }
        }

        private static void ExecLevelService(LogicPlayer logicPlayer, int itemId, int num)
        {
            CfgItem cfgItem = TableCenter.item.Get(itemId);
            int effectId = cfgItem?.ItemEffectID ?? 0;
            if (effectId == 0)
                return;

            var cfgItemEffect = TableCenter.systemEffect.Get(effectId);
            if ((EffectType)cfgItemEffect.Type != EffectType.ExecLevelService)
                return;

            LevelServiceModule.TriggerSystemServices(logicPlayer, cfgItemEffect.Params);
        }

        /// <summary>
        /// 执行手持道具的装备效果
        /// （进入关卡时应当调用，解锁新效果时需要先执行一次取下，再执行一次切入）
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="itemData"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void TriggerPortableAddEffect(LogicPlayer logicPlayer, LogicItemData itemData)
        {
            if (itemData == null || itemData.cfg.Type != ItemType.Portable)
            {
                return;
            }
            LevelServiceModule.TriggerSystemServices(logicPlayer, itemData.cfg.AddService);
            // 执行穿戴效果
            PortableData portableData = itemData.portableData;
            foreach (int partId in portableData.parts)
            {
                CfgPortablePart partCfg = TableCenter.portablePart.GetCfgByItemIdAndPartId(itemData.cid, partId);
                if (partCfg != null)
                {
                    portableData.triggeringParts.Add(partId);
                    LevelServiceModule.TriggerSystemServices(logicPlayer, partCfg.AddService);
                }
            }
        }

        /// <summary>
        /// 触发手持道具新增部件的效果
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="itemData"></param>
        public void TriggerPortableNewPartsEffect(LogicPlayer logicPlayer, LogicItemData itemData)
        {
            if (itemData == null || itemData.cfg.Type != ItemType.Portable)
            {
                return;
            }
            PortableData portableData = itemData.portableData;
            foreach (int partId in portableData.parts)
            {
                if (portableData.triggeringParts.Contains(partId))
                {
                    continue;
                }
                CfgPortablePart partCfg = TableCenter.portablePart.GetCfgByItemIdAndPartId(itemData.cid, partId);
                if (partCfg != null)
                {
                    portableData.triggeringParts.Add(partId);
                    LevelServiceModule.TriggerSystemServices(logicPlayer, partCfg.AddService);
                }
            }
        }

        /// <summary>
        /// 执行手持道具的取下效果
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="itemData"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void TriggerPortableRemoveEffect(LogicPlayer logicPlayer, LogicItemData itemData)
        {
            if (itemData == null || itemData.cfg.Type != ItemType.Portable)
            {
                return;
            }
            LevelServiceModule.TriggerSystemServices(logicPlayer, itemData.cfg.RemoveService);
            // 执行卸下效果
            PortableData portableData = itemData.portableData;
            foreach (int partId in portableData.parts)
            {
                if (portableData.triggeringParts.Remove(partId))
                {
                    CfgPortablePart partCfg = TableCenter.portablePart.GetCfgByItemIdAndPartId(itemData.cid, partId);
                    LevelServiceModule.TriggerSystemServices(logicPlayer, partCfg.RemoveService);
                }
            }
        }

        /// <summary>
        /// 执行手持道具使用效果
        /// </summary>
        /// <param name="logicPlayer"></param>
        /// <param name="itemData"></param>
        public void TriggerPortableUseEffect(LogicPlayer logicPlayer, LogicItemData itemData)
        {
            if (itemData == null || itemData.cfg.Type != ItemType.Portable)
            {
                return;
            }
            PortableData portableData = itemData.portableData;
            foreach (int partId in portableData.parts)
            {
                CfgPortablePart partCfg = TableCenter.portablePart.GetCfgByItemIdAndPartId(itemData.cid, partId);
                if (partCfg != null)
                {
                    LevelServiceModule.TriggerSystemServices(logicPlayer, partCfg.UseService);
                }
            }
        }

        #endregion
    }
}
